! Project TWS Matrixexponentiële
!
!
! MODULE AUXTEST
!
! Deze module bevat hulptesten, die de werking van de modules fftw en IO testen.
! 
! @author Roel Matthysen
! @version 2.0


module auxtest

    use IO
    use fftw
    implicit none
    private

    integer, parameter :: doubleprecision = kind(0.d0)
    public :: iotest, ffttest, pstat
        
    contains
        ! IOTEST
        !
        ! Deze routine test de IO module op de volgende manieren:
        ! -Lees een volle matrix uit een test file, en vergelijk met de hardcoded verwachte output
        ! -Lees een circulante matrix uit een test file, en vergelijk met de hardcoded verwachte output
        ! -Print een volle matrix, en print ook de verwachte uitkomst
        ! -Print een circulante matrix, en print ook de verwachte uitkomst
        !
        ! @since     2.0
        subroutine iotest()
            real(doubleprecision),allocatable :: A(:,:)
            real(doubleprecision),allocatable :: Ac(:)
            ! Test op lezen van volle matrices
            allocate(A(2,2))
            OPEN(32,file='testmatrices/readmatrix1.in')
            A=readmatrix(2,32,.true.)
            if(A(1,1)==1.0 .and. A(1,2)==2.0 .and. A(2,1)==3.0 .and. A(2,2)==4.0) then
                print *, 'Read full OK'
            else
                print *, 'Read full failed'
            endif
            close(32)
            ! Test op lezen van circulante matrices
            allocate(Ac(2))
            OPEN(32,file='testmatrices/readmatrix2.in')
            Ac=readmatrixc(2,32,.true.)
            if(Ac(1)==1.0 .and. Ac(2)==2.0) then
                print *, 'Read circ OK'
            else
                print *, 'Read circ failed'
            endif
            !Test op het printen van een volle matrix
            print *, 'print volle matrix:'
            call printresult(A)
            print *, 'resultaat moet zijn:'
            write(*,*) 2
            write(*,*) 1.0d0,2.0d0
            write(*,*) 3.0d0,4.0d0
            ! Test op het printen van een circulaire matrix
            print *, 'print circulaire matrix'
            call printresult(Ac)
            print *, 'resultaat moet zijn:'
            write(*,*) 'c2'
            write(*,*)    1.0d0
            write(*,*)  2.0d0
            deallocate(A)
            deallocate(Ac)
            close(32)
        end subroutine iotest
        
        ! FFTTEST
        !
        ! Deze routine test de module FFT, op de volgende manier:
        ! Voor een gegeven grootte, lees een invoermatrix en zijn fft uit een file. Vergelijk dan de berekende fft 
        ! met de uitgelezen fft en de berekende ifft met de oorspronkelijke waarde.
        !
        ! @since    2.0
        subroutine ffttest(ind)
            integer :: ind, size
            logical :: fftstatus, ifftstatus
            real(doubleprecision),allocatable :: Ac(:), Bc(:),Dc(:)
            complex(doubleprecision),allocatable :: Cc(:)
            CHARACTER(len = 30) :: fnamein
            CHARACTER(len = 32) :: fnameout, fnameoutb
            WRITE(fnamein,'(a,i1,a)')'testmatrices/testmatrixfft', ind, '.in'
              OPEN(32,file=fnamein)
            WRITE(fnameout,'(a,i1,a)') 'testmatrices/testmatrixfftr', ind, '.out'
            OPEN(33,file=fnameout)    
            WRITE(fnameoutb,'(a,i1,a)') 'testmatrices/testmatrixfftc', ind, '.out'
            OPEN(34,file=fnameoutb)    
            size = 10**ind
            allocate(Ac(size))
            allocate(Bc(size))
            allocate(Cc(size))
            allocate(Dc(size))
            Ac=readmatrixc(size,32,.true.)
            Bc=readmatrixc(size,33,.true.)
            Dc=readmatrixc(size,34,.true.)
            Cc=fft(Ac)
            fftstatus = comparefftw(real(Cc),Bc) .and. comparefftw(aimag(Cc),Dc)
            Bc=ifft(Cc)
            ifftstatus = comparefftw(Ac,Bc)
            write(6, '(a7,3x,i6,2x,a7,2x,a7)') 'Grootte',size,pstat(fftstatus),pstat(ifftstatus)
            deallocate(Ac)
            deallocate(Bc)
            deallocate(Cc)
            deallocate(Dc)
            close(32)
            close(33)
            close(34)
        end subroutine ffttest
        
        ! COMPAREFFTW
        !
        ! Hulpfunctie die gebruikt wordt om twee rijen (fft) met elkaar te vergelijken. Indien het maximale verschil 
        ! kleiner is dan een tolerantie, wordt True teruggegeven, anders False.
        !
        ! @param    A                De eerste rij, een ééndimensionale reële dubbele precisie matrix
        !
        ! @param    B                De tweede rij, een ééndimensionale reële dubbele precisie matrix
        !
        ! @result   OK               Een boolean, die aangeeft of het maximale verschil al dan niet onder de tolerantie
        !                            ligt.
        ! @since    2.0
        function comparefftw(A,B) result(OK)
            real(doubleprecision) :: A(:)
            real(doubleprecision) :: B(:)
            logical :: OK
            if (maxval(abs(A-B))<=(10.0**(-10))) then
                OK = .true.
            else
                OK = .false.
            endif
        end function
        
        ! pstat
        !
        ! Functie om een boodschap terug te geven voor een gegeven boolean.
        !
        ! @param    input            Een boolean, de status die geprint moet worden 
        !
        ! @result   status           Een string die 'OK' is als input true is, en 'failed! als input false is
        !
        ! @since    2.0
        function pstat(input) result(status)
            logical, intent(in) :: input
            character(len=7) :: status
            if(input) then 
                status = 'OK     '
            else
                status = 'failed!'
            endif
        end function
    
end module
